using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

/// <summary>
/// UGUI界面逻辑基类。
/// </summary>
public abstract class UGUIForm : UIFormLogic
{
    public const int DepthFactor = 100;
    private const float FadeTime = 0.3f;

    private Canvas m_CachedCanvas = null;
    private CanvasGroup m_CanvasGroup = null;
    private Transform m_Content;

    private List<Func<bool>> m_ReFirstCbs = new List<Func<bool>>();

    /// <summary>
    /// 获取原始深度。
    /// </summary>
    public int OriginalDepth
    {
        get;
        private set;
    }

    /// <summary>
    /// 获取当前深度。
    /// </summary>
    public int Depth
    {
        get
        {
            if (m_CachedCanvas != null)
            {
                return m_CachedCanvas.sortingOrder;
            }
            return 0;
        }
    }

    /// <summary>
    /// 获取CanvasGroup组件。
    /// </summary>
    public CanvasGroup CanvasGroup => m_CanvasGroup;

    /// <summary>
    /// 关闭界面（带淡出动画）。
    /// </summary>
    [ContextMenu("Close")]
    public void Close()
    {
        Close(true);
    }

    /// <summary>
    /// 关闭界面。
    /// </summary>
    /// <param name="ignoreFade">是否忽略淡出动画。</param>
    public void Close(bool ignoreFade)
    {
        StopAllCoroutines();

        if (ignoreFade)
        {
            if (UIForm != null)
            {
                UIManager.Instance.CloseUIForm(UIForm.SerialId);
            }
        }
        else
        {
            StartCoroutine(CloseCo(FadeTime));
        }
    }

#if UNITY_EDITOR
    [ContextMenu("Release")]
    private void Release()
    {
        if (UIForm != null)
        {
            UIManager.Instance.CloseUIForm(UIForm.SerialId);
        }
    }
#endif

    /// <summary>
    /// 初始化界面（框架内部调用）。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    protected internal override void OnInit(object userData)
    {
        base.OnInit(userData);

        // 获取或添加Canvas组件
        m_CachedCanvas = gameObject.GetOrAddComponent<Canvas>();
        m_CachedCanvas.overrideSorting = true;
        OriginalDepth = m_CachedCanvas.sortingOrder;

        // 获取或添加CanvasGroup组件
        m_CanvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();

        // 设置RectTransform属性（全屏）
        RectTransform rectTransform = GetComponent<RectTransform>();
        if (rectTransform != null)
        {
            rectTransform.anchorMin = Vector2.zero;
            rectTransform.anchorMax = Vector2.one;
            rectTransform.anchoredPosition = Vector2.zero;
            rectTransform.sizeDelta = Vector2.zero;
        }

        // 获取或添加GraphicRaycaster组件
        gameObject.GetOrAddComponent<GraphicRaycaster>();

        // 查找Content子节点
        m_Content = transform.Find("Content");

        // 调用子类可重写的OnInit方法
        OnInitInternal(userData);
    }

    /// <summary>
    /// 初始化界面（子类可重写此方法）。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    protected virtual void OnInitInternal(object userData)
    {
    }

    /// <summary>
    /// 回收界面（框架内部调用）。
    /// </summary>
    protected internal override void OnRecycle()
    {
        OnRecycleInternal();
        base.OnRecycle();
        CleanReFirstCbs();
    }

    /// <summary>
    /// 回收界面（子类可重写此方法）。
    /// </summary>
    protected virtual void OnRecycleInternal()
    {
    }

    /// <summary>
    /// 打开界面（框架内部调用）。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    protected internal override void OnOpen(object userData)
    {
        base.OnOpen(userData);

        if (m_CanvasGroup != null)
        {
            m_CanvasGroup.alpha = 1f;
        }

        // 调用子类可重写的OnOpen方法
        OnOpenInternal(userData);
    }

    /// <summary>
    /// 打开界面（子类可重写此方法）。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    protected virtual void OnOpenInternal(object userData)
    {
    }

    /// <summary>
    /// 打开界面（带打开模式）。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    /// <param name="openMode">打开模式。</param>
    public virtual void OnOpen(object userData, UGUIFormOpenMode openMode = UGUIFormOpenMode.None)
    {
        base.OnOpen(userData);
        
        switch (openMode)
        {
            case UGUIFormOpenMode.None:
                if (m_CanvasGroup != null)
                {
                    m_CanvasGroup.alpha = 1f;
                }
                break;
            case UGUIFormOpenMode.Fade:
                if (m_CanvasGroup != null)
                {
                    m_CanvasGroup.alpha = 0f;
                    StopAllCoroutines();
                    StartCoroutine(m_CanvasGroup.FadeToAlpha(1f, FadeTime));
                }
                break;
            case UGUIFormOpenMode.Popup:
                StopAllCoroutines();
                Popup();
                break;
        }
    }

    /// <summary>
    /// 弹出动画。
    /// </summary>
    private void Popup()
    {
        if (m_Content == null)
            return;

        m_Content.transform.localScale = Vector3.one * 0.8f;
        m_Content.transform.DOScale(1.1f, 0.1f).SetEase(Ease.InOutQuad).OnComplete(() =>
        {
            m_Content.transform.DOScale(1f, 0.1f).SetEase(Ease.InOutQuad);
        });
    }

    /// <summary>
    /// 关闭界面（框架内部调用）。
    /// </summary>
    /// <param name="isShutdown">是否是关闭游戏时触发。</param>
    /// <param name="userData">用户自定义数据。</param>
    protected internal override void OnClose(bool isShutdown, object userData)
    {
        OnCloseInternal(isShutdown, userData);
        base.OnClose(isShutdown, userData);

        if (m_CanvasGroup != null)
        {
            m_CanvasGroup.alpha = 0f;
        }
        
        CleanReFirstCbs();
    }

    /// <summary>
    /// 关闭界面（子类可重写此方法）。
    /// </summary>
    /// <param name="isShutdown">是否是关闭游戏时触发。</param>
    /// <param name="userData">用户自定义数据。</param>
    protected virtual void OnCloseInternal(bool isShutdown, object userData)
    {
    }

    /// <summary>
    /// 暂停界面。
    /// </summary>
    protected internal override void OnPause()
    {
        base.OnPause();

        if (m_CanvasGroup != null)
        {
            m_CanvasGroup.alpha = 0f;
        }
    }

    /// <summary>
    /// 恢复界面。
    /// </summary>
    protected internal override void OnResume()
    {
        base.OnResume();

        if (m_CanvasGroup != null)
        {
            m_CanvasGroup.alpha = 1f;
        }
    }

    /// <summary>
    /// 界面被遮挡。
    /// </summary>
    protected internal override void OnCover()
    {
        base.OnCover();
    }

    /// <summary>
    /// 界面遮挡恢复。
    /// </summary>
    protected internal override void OnReveal()
    {
        base.OnReveal();

        if (m_CanvasGroup != null)
        {
            m_CanvasGroup.alpha = 1f;
        }
    }

    /// <summary>
    /// 界面激活。
    /// </summary>
    /// <param name="userData">用户自定义数据。</param>
    protected internal override void OnRefocus(object userData)
    {
        base.OnRefocus(userData);
    }

    /// <summary>
    /// 界面轮询。
    /// </summary>
    /// <param name="elapseSeconds">逻辑流逝时间，以秒为单位。</param>
    /// <param name="realElapseSeconds">真实流逝时间，以秒为单位。</param>
    protected internal override void OnUpdate(float elapseSeconds, float realElapseSeconds)
    {
        base.OnUpdate(elapseSeconds, realElapseSeconds);
    }

    /// <summary>
    /// 界面深度改变。
    /// </summary>
    /// <param name="uiGroupDepth">界面组深度。</param>
    /// <param name="depthInUIGroup">界面在界面组中的深度。</param>
    protected internal override void OnDepthChanged(int uiGroupDepth, int depthInUIGroup)
    {
        int oldDepth = Depth;
        base.OnDepthChanged(uiGroupDepth, depthInUIGroup);
        
        if (m_CachedCanvas != null)
        {
            int deltaDepth = 3000 * uiGroupDepth + DepthFactor * depthInUIGroup - oldDepth + OriginalDepth;
            m_CachedCanvas.sortingOrder += deltaDepth;
        }
    }

    /// <summary>
    /// 前面的界面已经被关闭，当前界面重新回到当前Group的第一层时。
    /// </summary>
    public override void OnReFirst()
    {
        base.OnReFirst();
        CheckReFirstCbs();
    }

    /// <summary>
    /// 关闭协程（带淡出动画）。
    /// </summary>
    /// <param name="duration">淡出持续时间。</param>
    private IEnumerator CloseCo(float duration)
    {
        Animator animator = GetComponent<Animator>();
        if (animator != null)
        {
            string anim = "Close";
            animator.Play(anim);
            yield return null;
            var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
            if (stateInfo.IsName(anim))
                duration = stateInfo.length;
        }
        
        if (m_CanvasGroup != null)
        {
            yield return m_CanvasGroup.FadeToAlpha(0f, duration);
        }
        
        if (UIForm != null)
        {
            UIManager.Instance.CloseUIForm(UIForm.SerialId);
        }
    }

    /// <summary>
    /// 检查ReFirst回调。
    /// </summary>
    protected void CheckReFirstCbs()
    {
        var count = m_ReFirstCbs.Count;
        for (int i = 0; i < count; i++)
        {
            if (m_ReFirstCbs.Count == 0)
                break;
                
            var func = m_ReFirstCbs[0];
            m_ReFirstCbs.RemoveAt(0);
            if (func != null && func())
                break;
        }
#if UNITY_EDITOR
        if (count > 0 && m_ReFirstCbs.Count >= count)
        {
            Logger.LogWarning("CheckReFirstCbs", "可能存在重复添加");
        }
#endif
    }

    /// <summary>
    /// 清除ReFirst回调。
    /// </summary>
    protected void CleanReFirstCbs()
    {
        m_ReFirstCbs.Clear();
    }

    /// <summary>
    /// 添加ReFirst回调。
    /// </summary>
    /// <param name="func">回调函数，返回true表示已处理，不再执行后续回调。</param>
    /// <param name="ignoreRepeat">是否忽略重复添加。</param>
    protected void AddReFirstCb(Func<bool> func, bool ignoreRepeat = true)
    {
        if (func == null)
            return;
            
        if (m_ReFirstCbs.Contains(func))
        {
#if UNITY_EDITOR
            Logger.LogWarning("AddReFirstCb", "可能重复添加回调");
#endif
            if (ignoreRepeat)
                m_ReFirstCbs.Remove(func);
        }
        m_ReFirstCbs.Add(func);
    }

    /// <summary>
    /// 插入ReFirst回调。
    /// </summary>
    /// <param name="index">插入位置。</param>
    /// <param name="func">回调函数。</param>
    /// <param name="ignoreRepeat">是否忽略重复添加。</param>
    protected void InsertReFirstCb(int index, Func<bool> func, bool ignoreRepeat = true)
    {
        if (func == null)
            return;
            
        if (m_ReFirstCbs.Contains(func))
        {
#if UNITY_EDITOR
            Logger.LogWarning("InsertReFirstCb", "可能重复添加回调");
#endif
            if (ignoreRepeat)
                m_ReFirstCbs.Remove(func);
        }
        m_ReFirstCbs.Insert(index, func);
    }

    /// <summary>
    /// 移除ReFirst回调。
    /// </summary>
    /// <param name="func">回调函数。</param>
    /// <returns>是否成功移除。</returns>
    protected bool RmReFirstCb(Func<bool> func)
    {
        return m_ReFirstCbs.Remove(func);
    }
}

/// <summary>
/// UGUIForm打开模式。
/// </summary>
public enum UGUIFormOpenMode
{
    /// <summary>
    /// 无动画。
    /// </summary>
    None,

    /// <summary>
    /// 淡入动画。
    /// </summary>
    Fade,

    /// <summary>
    /// 弹出动画。
    /// </summary>
    Popup
}
